package com.zmn.oms.zmn.business.impl.collectionnotpay;

import avro.shaded.com.google.common.collect.Lists;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.utils.StringUtils;
import com.zmn.account.common.constant.AccountConsts;
import com.zmn.account.common.constant.IdentityConsts;
import com.zmn.account.common.dto.account.AccountInfoDIO;
import com.zmn.account.common.dto.account.AccountInfoDRO;
import com.zmn.account.dubbo.interfaces.account.AccountListRemoteService;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.base.common.data.common.query.tags.TagsQuery;
import com.zmn.base.common.data.dubbo.interfaces.tags.TagsListRemoteService;
import com.zmn.base.engineer.common.dro.foreign.engineer.ForeignEngineerBasicInfoDRO;
import com.zmn.base.engineer.dubbo.interfaces.foreign.EngineerListRemoteService;
import com.zmn.base.plat.engine.common.util.object.ToArrayUtil;
import com.zmn.base.plat.engine.common.util.response.DubboResponseUtils;
import com.zmn.base.remind.common.consts.MqConst;
import com.zmn.base.remind.common.enums.AppTypeEnum;
import com.zmn.base.remind.common.enums.ScenesTypeEnum;
import com.zmn.base.remind.common.model.remind.RemindRequestDIO;
import com.zmn.base.remind.common.model.remind.VoiceVariateDIO;
import com.zmn.cms.dubbo.constant.DubboConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.consts.GlobalConsts;
import com.zmn.erp.common.newbiz.enums.PlatCompanyEnum;
import com.zmn.framework.mq.ZmnMQException;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.messageV1.common.MessageSendBaseService;
import com.zmn.oms.business.interfaces.work.tag.OrderTagBService;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.model.dto.messageV1.AppMessageDTO;
import com.zmn.oms.model.dto.tag.OrderTagAddDTO;
import com.zmn.oms.model.dto.work.masterwork.CompleteDTO;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.pay.OrderPayService;
import com.zmn.oms.services.interfaces.work.OrderWorkAmountService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.collectionnotpay.CollectionNotPayBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.oms.zmn.business.interfaces.work.masterwork.ZsMasterWorkBService;
import com.zmn.pay.common.constant.PayConsts;
import com.zmn.pay.gateway.common.constants.OrderTypeConsts;
import com.zmn.pay.gateway.common.enums.AppEnum;
import com.zmn.pay.gateway.common.enums.OrderStatusEnum;
import com.zmn.pay.gateway.common.model.dio.order.TransferDIO;
import com.zmn.pay.gateway.common.model.dro.PayOrderDRO;
import com.zmn.pay.gateway.dubbo.interfaces.trade.TransferModifyRemoteService;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.common.dio.TrackWorkPageQueryDIO;
import com.zmn.track.dubbo.dto.CompleteTrackDIO;
import com.zmn.track.dubbo.dto.TrackWorkDIO;
import com.zmn.track.dubbo.dto.TrackWorkDRO;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
@Service
public class CollectionNotPayBServiceImpl implements CollectionNotPayBService {
    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;
    /**
     * 跟单支付
     */
    private static final Integer PAY_TYPE_DOCUMENTARY = 1;
    private static final Integer ONE_TYPE_ID = 5001;


    /**
     * 违约金支付
     */
    private static final Integer PAY_TYPE_BREAK_A_CONTRACT = 2;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private AccountListRemoteService accountListRemoteService;

    @DubboReference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected TagsListRemoteService tagsListRemoteService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private TransferModifyRemoteService transferModifyRemoteService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;
    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    EngineerListRemoteService engineerListRemoteService;
    @NacosValue(value = "${collection.notPay.filter.city:''}", autoRefreshed = true)
    public String excludeCity = "";
    @NacosValue(value = "${collection.notPay.test.order:false}", autoRefreshed = true)
    public Boolean testOrder = Boolean.FALSE;
    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    ZsMasterWorkBService zsMasterWorkBService;
    @Autowired
    OrderLogBService orderLogBService;
    @Autowired
    OrderPayService orderPayService;
    @Autowired
    OrderWorkAmountService orderWorkAmountService;
    @Autowired
    WorkFlowContextBService workFlowContextBService;
    @Autowired
    ZmnMQSender zmnMQSender;
    @Autowired
    MessageSendBaseService messageSendBaseService;
    @Autowired
    OrderTagBService orderTagBService;

    @Override

    public void collectionNotPay() {
        //获取两天前所有的跟单列表
        Date nowDefer = DateUtil.getNowDefer(-2);
        Date endDate = DateUtil.addMonth(nowDefer, -3);
        TrackWorkPageQueryDIO trackWorkQueryDIO = new TrackWorkPageQueryDIO();
        trackWorkQueryDIO.setTrackContentIdList(Arrays.asList(TrackConfigConsts.TRACK_CONTENT_ID_ENGINEER_MONEY_NO_PAY));
        trackWorkQueryDIO.setTrackStatusList(Lists.newArrayList(TrackConsts.TRACK_STATUS_PENDING, TrackConsts.TRACK_STATUS_PROCESSING));
        trackWorkQueryDIO.setOrderField("createTime");
        trackWorkQueryDIO.setStartCreatTime(endDate);
        trackWorkQueryDIO.setEndCreatTime(nowDefer);
        trackWorkQueryDIO.setPageSize(1000);

        //每次只处理上周以前的数据
        List<TrackWorkDRO> listTrackWork = DubboResponseUtils.resultListToThrow(() -> trackWorkListRemoteService.listTrackWorkPageByQuery(trackWorkQueryDIO));
        log.info("#CollectionNotPay# listTrackWork：{},入参：{} ,处理条数：{}", listTrackWork.size(), JSON.toJSONString(trackWorkQueryDIO), listTrackWork.size());
        if (CollectionUtil.isNullOrEmpty(listTrackWork)) {
            return;
        }
        List<Integer> listExcludeCity = new ArrayList<>();
        if (Strings.isNotBlank(excludeCity)) {
            listExcludeCity = ToArrayUtil.toIntegerList(excludeCity);
        }
        // 并行处理获取质保金支付订单
        for (TrackWorkDRO workDRO : listTrackWork) {
            try {
                this.workDROProcess(listExcludeCity, workDRO);
            } catch (Exception e) {
                log.error("#CollectionNotPay# 跟单ID：{}  订单{},处理异常，异常信息：{}", workDRO.getTrackWorkId(), workDRO.getOrderId(), e.getMessage());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void workDROProcess(List<Integer> listExcludeCity, TrackWorkDRO workDRO) {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(workDRO.getOrderId(), workDRO.getWorkId());
        log.info("#CollectionNotPay# 跟单ID：{} 步骤", workDRO.getTrackWorkId());

        // 判断是否是执行测试单 并于上线后测试
        if (Objects.equals(GlobalConsts.TWO, orderWork.getTest())) {
            return;
        }
        if (Objects.equals(Boolean.FALSE, checkOrderAvailable(orderWork))) {
            return;
        }
        // 金额小于0 的不需要支付
        if (workDRO.getAmount() <= GlobalConsts.NONE || Objects.equals(workDRO.getStatus(), TrackConsts.TRACK_STATUS_FINISHED)) {
            return;
        }
        // 过滤产品组信息
        if (CollectionUtil.isNotNullOrEmpty(listExcludeCity) && !listExcludeCity.contains(orderWork.getCityId())) {
            log.info("#CollectionNotPay# 跟单ID：{} 步骤1 listExcludeCity {}", orderWork.getOrderId(), JSON.toJSONString(listExcludeCity));
            return;
        }
        if (getOrderPayNotes(orderWork.getOrderId())) {
            this.completeTrack(workDRO, String.format("已使用质保金支付订单，重复发起的收款未支付跟单系统自动完成(%s)", workDRO.getTrackWorkId()));
            return;
        }

        // 违约金金额 = 收款未支付金额 * 10% ≥ 500 ？ 500 ：收款未支付金额 * 10%
        Integer breakContractAmount = getBreakAContractAmount(workDRO.getAmount());
        // 质保金不足的时候不做处理
        AccountInfoDRO accountInfo = getAccountInfo(orderWork.getMasterId(), orderWork.getMasterName(), orderWork.getOrderId());
        log.info("#CollectionNotPay# 订单号：{} 步骤2 计算违约金成功 ：{},跟单金额：{}", orderWork.getOrderId(), breakContractAmount, workDRO.getAmount());
        if (accountInfo.getBalanceAmount() < (workDRO.getAmount() + breakContractAmount)) {
            return;
        }
        if (!Objects.equals(orderWork.getMasterAmount(), workDRO.getAmount())) {
            log.info("#CollectionNotPay# 工程师收款金额不等于跟单金额,不收取质保金");
            return;
        }
        // 质保金支付订单金额
        Boolean payStatus = this.warrantyGoldPay(orderWork, workDRO.getAmount(), accountInfo.getAccountId(), PAY_TYPE_DOCUMENTARY);

        // 添加标签
        this.addBondPayTag(orderWork, payStatus);
        if (Objects.equals(Boolean.FALSE, payStatus)) {
            return;
        }

        log.debug("#CollectionNotPay# 订单号：{} 步骤3 质保金支付订单金额：{}", orderWork.getOrderId(), workDRO.getAmount());
        // 订单节点日志记录
        String warrantyOrderlog = getWarrantyOrderLog(workDRO.getAmount(), payStatus ? "成功" : "失败");
        this.orderWorkWarrantyAmountLog(orderWork, OrderLogConsts.ORDER_LOG_TYPE_WARRANTY_AMOUNT, warrantyOrderlog);

        // 违约金支付
        Boolean breakAContractPayStatus = this.warrantyGoldPay(orderWork, breakContractAmount, accountInfo.getAccountId(), PAY_TYPE_BREAK_A_CONTRACT);
        log.debug("#CollectionNotPay# 订单号：{} 步骤5 质保金支付违约金：{}", orderWork.getOrderId(), workDRO.getAmount());
        warrantyOrderlog = getWarrantyOrderLog(breakContractAmount, (breakAContractPayStatus ? "违约金成功" : "违约金失败"));
        this.orderWorkWarrantyAmountLog(orderWork, OrderLogConsts.ORDER_LOG_TYPE_WARRANTY_AMOUNT, warrantyOrderlog);

        // 违约金支付失败再次支付
        if (Objects.equals(Boolean.FALSE, breakAContractPayStatus)) {
            sendPayBreakContractAmount(orderWork.getOrderId(), orderWork.getWorkId(), breakContractAmount);
        }
        this.completeTrack(workDRO, "");
        // 跟单支付成功并订单金额一致是完成订单和跟单

        this.completeOrder(orderWork, workDRO.getAmount());
        log.debug("#CollectionNotPay# 订单号：{} 步骤7 完结订单跟单：{}", orderWork.getOrderId(), workDRO.getAmount());

    }

    /**
     * 添加质保金扣款标签
     * @param orderWork
     * @param success
     */
    private void addBondPayTag(OrderWork orderWork, boolean success) {
        if (Objects.isNull(orderWork)) {
            return;
        }

        int tagId = success ? OrderTagConsts.TAG_ID_BONDPAY_SUCCESS : OrderTagConsts.TAG_ID_BONDPAY_FAILED;
        OrderTagAddDTO orderTagAddDTO = new OrderTagAddDTO();
        orderTagAddDTO.setOrderId(orderWork.getOrderId());
        orderTagAddDTO.setWorkId(orderWork.getWorkId());
        orderTagAddDTO.setTagIdList(Lists.newArrayList(tagId));

        try {
            orderTagBService.addOrderTag(orderTagAddDTO);
        } catch (OmsBaseException e) {
            log.error("添加质保金扣款标签失败，{}", e.getMessage());
        }
    }

    /**
     * 生成质保金支付失败跟单和修改平台预售金额及记录日志
     *
     * @param amount    金额
     * @param orderWork 工单
     */
    private void generateTrackWorkAndUpdatePrePayAmount(Integer amount, OrderWork orderWork) {
        // 塞入平台预收金
        this.updatePrepayAmount(amount, orderWork, null);
        // 生成质保金支付跟单
        TrackWorkDIO trackWorkDIO = new TrackWorkDIO();
        trackWorkDIO.setWorkId(orderWork.getWorkId());
        trackWorkDIO.setOrderId(orderWork.getOrderId());
        trackWorkDIO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
        trackWorkDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        trackWorkDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        trackWorkDIO.setTrackContentId(TrackConfigConsts.TRACK_CONTENT_ID_WARRANTY_COMPLETE_FAIL);
        trackWorkModifyRemoteService.addTrack(trackWorkDIO);
        StringBuilder content = new StringBuilder();
        content.append("完成结果 ：失败\n");
        content.append("失败缘由：质保金支付金额不等于应收金额");
        this.orderWorkWarrantyAmountLog(orderWork, OrderLogConsts.ORDER_LOG_TYPE_COMPLETE, content.toString());
    }

    private void updatePrepayAmount(Integer amount, OrderWork orderWork, Integer payStatus) {
        int masterAmount = 0;
        if (Objects.nonNull(orderWork.getMasterAmount())) {
            masterAmount = orderWork.getMasterAmount() - amount;
        }
        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setPrepayStatus(PayConsts.PAY_STATUS_DONE);
        if (Objects.nonNull(orderWork.getPrepayAmount())) {
            amount = orderWork.getPrepayAmount() + amount;
        }
        updateOrderWork.setPrepayAmount(amount);
        updateOrderWork.setOrderId(orderWork.getOrderId());
        updateOrderWork.setWorkId(orderWork.getWorkId());
        updateOrderWork.setMasterAmount(masterAmount);
        if (NumberUtil.isNotNullOrZero(payStatus)) {
            updateOrderWork.setPayTime(new Date());
            updateOrderWork.setMasterPayTime(new Date());
            updateOrderWork.setMasterPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_DEPOSIT);
            updateOrderWork.setMasterPayStatus(payStatus);
            updateOrderWork.setPayStatus(payStatus);
        }
        orderWorkAmountService.updatePrepayAmountAndMasterAmountPay(updateOrderWork);
    }

    /**
     * 完成跟单
     *
     * @param workDRO 跟单信息
     */
    private void completeTrack(TrackWorkDRO workDRO, String operatorRemark) {
        // 先完成跟单
        CompleteTrackDIO trackDIO = BeanMapper.map(workDRO, CompleteTrackDIO.class);
        trackDIO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
        trackDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        trackDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        trackDIO.setOperatorRemark(operatorRemark);
        log.info("#CollectionNotPay# 订单号：{} 步骤6 收款未支付使用保质金支付 出参：{}", workDRO.getOrderId(), JSON.toJSONString(trackDIO));
        ResponseDTO responseDTO = trackWorkModifyRemoteService.completeTrack(trackDIO);
        log.info("#CollectionNotPay# 订单号：{} 步骤6 收款未支付使用保质金支付 出参：{}", workDRO.getOrderId(), JSON.toJSONString(responseDTO));
    }

    @Override
    public void retryPayBreakContractAmount(Long workId, Long orderId, Integer amount) {
        // 获取订单
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            return;
        }
        AccountInfoDRO accountInfo = this.getAccountInfo(orderWork.getMasterId(), orderWork.getMasterName(), orderId);
        if (accountInfo.getBalanceAmount() < amount) {
            return;
        }
        this.warrantyGoldPay(orderWork, amount, accountInfo.getAccountId(), PAY_TYPE_BREAK_A_CONTRACT);
    }


    /**
     * 支付
     *
     * @param orderWork 订单信息
     * @param amount    支付金额
     * @param accountId 付款账号
     * @param payType   支付类型
     */
    private Boolean warrantyGoldPay(OrderWork orderWork, Integer amount, Long accountId, Integer payType) {
        if (amount <= GlobalConsts.NONE) {
            return false;
        }
        Integer tradeCategId = OrderTypeConsts.AccountTradeCategEnum.TRANSFER_DEDUCT_ORDER_PAY.getThirdId();
        if (Objects.equals(payType, PAY_TYPE_BREAK_A_CONTRACT)) {
            tradeCategId = OrderTypeConsts.AccountTradeCategEnum.TRANSFER_DEDUCT_ORDER_PAY_PUNISH.getThirdId();
        }
        TransferDIO transferDIO = new TransferDIO();
        transferDIO.setAppBizNo(String.valueOf(orderWork.getOrderId()));
        transferDIO.setAppId(AppEnum.APP_OMS.getAppId());
        transferDIO.setAmount(amount);
        transferDIO.setTradeCategId(tradeCategId);
        transferDIO.setAppSubBizNo(String.format("%d-%d-%d", orderWork.getOrderId(), payType, tradeCategId));
        transferDIO.setPlat(orderWork.getPlat());
        transferDIO.setAppName(AppEnum.APP_OMS.getAppName());
        transferDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        transferDIO.setOperator("系统");
        transferDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        transferDIO.setAccountId(accountId);
        transferDIO.setToAccountId(getToAccountId(orderWork.getPlat()));
        transferDIO.setFromAccountId(accountId);
        PayOrderDRO payOrderDRO = DubboResponseUtils.resultToNull(() -> transferModifyRemoteService.transfer(transferDIO));
        log.info("#CollectionNotPay# 订单号：{} 步骤支付 出参：{}", orderWork.getOrderId(), JSON.toJSONString(payOrderDRO));
        if (Objects.isNull(payOrderDRO) || !Objects.equals(payOrderDRO.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_SUCCESS.getCode())) {
            return Boolean.FALSE;
        }
        if (Objects.equals(payType, PAY_TYPE_DOCUMENTARY)) {
            this.savePayRecord(orderWork, transferDIO, amount);
        }
        return Boolean.TRUE;
    }

    /**
     * 根据平台获取收款账户
     */
    private Long getToAccountId(Integer plat) {
        AccountInfoDIO dio = new AccountInfoDIO();
        dio.setAccountCategId(AccountConsts.ACCOUNT_CATEG_TRADE_FUND);
        dio.setIdentityId(IdentityConsts.ACCOUNT_IDENTITY_ID_HEAD_COMPANY);
        dio.setIdentityObjectId((long) PlatCompanyEnum.getCompanyIdByPlat(plat));
        dio.setOperatorId(1L);
        dio.setOperator("系统");
        dio.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        AccountInfoDRO accountInfo = DubboResponseUtils.resultToThrow(() -> accountListRemoteService.getAccountInfo(dio));
        log.debug("#CollectionNotPay# 收款未支付使用收款方：{}", accountInfo.getAccountId());

        return accountInfo.getAccountId();
    }

    /**
     * 获取工程师质保金余额及账户
     *
     * @param masterId   工程师id
     * @param masterName 工程师名称
     * @param orderId    订单id
     * @return com.zmn.account.common.dto.account.AccountInfoDRO
     */
    private AccountInfoDRO getAccountInfo(Integer masterId, String masterName, Long orderId) {
        AccountInfoDIO dio = new AccountInfoDIO();
        dio.setAccountCategId(AccountConsts.ACCOUNT_CATEG_DEPOSIT);
        dio.setIdentityId(IdentityConsts.ACCOUNT_IDENTITY_ID_MASTER);
        dio.setIdentityObjectId((long) masterId);
        dio.setOperatorId((long) masterId);
        dio.setOperator(masterName);
        dio.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
        AccountInfoDRO accountInfo = DubboResponseUtils.resultToThrow(() -> accountListRemoteService.getAccountInfo(dio));
        return accountInfo;
    }

    /**
     * 计算违约金
     *
     * @param amount 金额
     * @return java.lang.Integer
     */
    private Integer getBreakAContractAmount(Integer amount) {
        if (NumberUtil.isNullOrZero(amount)) {
            return 0;
        }
        Integer minAmount = 500;
        Integer scale = 10;
        TagsQuery tagsQuery = new TagsQuery();
        tagsQuery.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        tagsQuery.setOneTypeId(ONE_TYPE_ID);
        tagsQuery.setStatus(GlobalConsts.YES);
        List<TagsDRO> tagsDROS = DubboResponseUtils.resultToNull(() -> tagsListRemoteService.listByQuery(tagsQuery));
        if (CollectionUtil.isNotNullOrEmpty(tagsDROS)) {
            TagsDRO tagsDRO = tagsDROS.get(GlobalConsts.NONE);
            minAmount = NumberUtil.isNullOrZero(tagsDRO.getThreeTypeId()) ? minAmount : tagsDRO.getThreeTypeId();
            scale = NumberUtil.isNullOrZero(tagsDRO.getTwoTypeId()) ? scale : tagsDRO.getTwoTypeId();
        }
        BigDecimal divide = new BigDecimal(scale).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal maxAmount = new BigDecimal(amount).multiply(divide).setScale(2, RoundingMode.HALF_UP);
        return Math.min(maxAmount.intValue(), minAmount * 100);
    }

    /**
     * 校验订单是否满足条件
     *
     * @param orderWork 订单
     * @return java.lang.Boolean
     */
    private Boolean checkOrderAvailable(OrderWork orderWork) {
        if (Objects.isNull(orderWork)) {
            return Boolean.FALSE;
        }
        // 判断订单是否是进行中的
        boolean orderStatus = Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING);
        if (Objects.equals(Boolean.FALSE, orderStatus)) {
            return Boolean.FALSE;
        }
        // 判断是否存在公工程师
        if (NumberUtil.isNullOrZero(orderWork.getMasterId()) && StringUtils.isBlank(orderWork.getMasterName())) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 违约金支付失败重试mq消息
     *
     * @param orderId              订单id
     * @param workId               工单id
     * @param breakAContractAmount 支付金额
     */
    public void sendPayBreakContractAmount(Long orderId, Long workId, Integer breakAContractAmount) {
        // 发送APP消息
        // 10 分钟后拍断是否已经改了状态
        String key = String.format("sendPayBreakContractAmount_%s_%s_%s", workId, orderId, breakAContractAmount);
        JSONObject message = new JSONObject();
        message.put("amount", breakAContractAmount);
        message.put("workId", workId);
        message.put("orderId", orderId);
        String content = JSON.toJSONString(message);
        long time = System.currentTimeMillis() + 60 * 1000;
        zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, MessageQueueTagConsts.ZMN_TAG_PAY_BREAK_CONTRACT_AMOUNT, key, content, time);
        log.info("#omsOrderWarningNewsBService# 步骤4,orderId：{},订单超时发送延迟MQ消息：key:[{}],message=>{}", orderId, key, content);

    }

    /**
     * 保存订单节点日志
     *
     * @param orderWork 订单信息
     * @param textName  支付类型名称
     */
    private void orderWorkWarrantyAmountLog(OrderWork orderWork, Integer logType, String textName) {
        if (Objects.isNull(orderWork)) {
            return;
        }
        OrderLog orderLog = new OrderLog();
        orderLog.setWorkId(orderWork.getWorkId());
        orderLog.setOrderId(orderWork.getOrderId());
        orderLog.setType(logType);
        orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(logType));
        orderLog.setBeforeStatus(orderWork.getStatus());
        orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setBeforeResultStatus(orderWork.getResultStatus());
        orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        orderLog.setAfterStatus(orderWork.getStatus());
        orderLog.setAfterStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setAfterResultStatus(orderWork.getResultStatus());
        orderLog.setAfterResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        orderLog.setCreateTime(new Date());
        orderLog.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        orderLog.setOperator("系统");
        orderLog.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        orderLog.setContent(textName);
        log.info("#CollectionNotPay# 订单号：{} 步骤保存日志", orderWork.getOrderId());
        orderLogBService.save(orderLog);
    }

    private String getWarrantyOrderLog(Integer amount, String textName) {
        StringBuilder content = new StringBuilder();
        content.append("工程师质保金支付 ");
        content.append(textName + ":");
        content.append(NumberUtil.convertMoneyToYuan(amount));
        content.append("元");
        return content.toString();
    }

    /**
     * 保存支付记录
     *
     * @param orderWork 订单信息
     * @param amount    支付金额
     */
    private void savePayRecord(OrderWork orderWork, TransferDIO transferDIO, Integer amount) {
        OrderPay orderPay = new OrderPay();
        orderPay.setOrderId(orderWork.getOrderId());
        orderPay.setWorkId(orderWork.getWorkId());
        orderPay.setPayPlat(orderWork.getPlat());
        orderPay.setAmountType(OrderPayConsts.ORDER_PAY_MASTER);
        orderPay.setTradeType(PayConsts.PAY_TRADE_TYPE_INTIME);
        orderPay.setPayStatus(PayConsts.PAY_STATUS_DONE);
        orderPay.setPayType(PayConsts.PAY_TYPE_INTO);
        orderPay.setPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_DEPOSIT);
        orderPay.setMergeInnerTradeNo("");
        orderPay.setMergePayOutTradeNo("");
        orderPay.setMergeAmount(0);
        orderPay.setInnerTradeNo("");
        orderPay.setPayOutTradeNo("");
        orderPay.setPayTime(new Date());
        orderPay.setImageUrls("");
        orderPay.setPayerType(0);
        orderPay.setPayerId(0L);
        orderPay.setPayerAccountId(transferDIO.getFromAccountId());
        orderPay.setPayerThirdAccount("");
        orderPay.setPayerThirdAccountName("");
        orderPay.setPayerThirdAccountBank("");
        orderPay.setPayeeType(0);
        orderPay.setPayeeId(0L);
        orderPay.setPayeeAccountId(0L);
        orderPay.setPayeeThirdAccount("");
        orderPay.setPayeeThirdAccountName("");
        orderPay.setPayeeThirdAccountBank("");
        orderPay.setRefundImageData("");
        orderPay.setAmount(amount);
        orderPay.setLongitude(0.0D);
        orderPay.setLatitude(0.0D);
        orderPay.setCreater("系统");
        orderPay.setUpdater("系统");
        orderPay.setCreateTime(new Date());
        orderPay.setUpdateTime(new Date());
        log.info("#CollectionNotPay# 订单号：{} 步骤质保金支付保存支付记录", orderWork.getOrderId());
        orderPayService.insertOrderPay(orderPay);
    }

    /**
     * 完成订单并完成跟单
     *
     * @param orderWork 订单信息
     * @param amount
     */
    private void completeOrder(OrderWork orderWork, Integer amount) {

        try {
            // 修改订单信息
            this.updatePrepayAmount(orderWork.getMasterAmount(), orderWork, PayConsts.PAY_STATUS_DONE);
            // 自动完成
            CompleteDTO completeDTO = new CompleteDTO();
            completeDTO.setOrderId(orderWork.getOrderId());
            completeDTO.setWorkId(orderWork.getWorkId());
            zsMasterWorkBService.completeOrder(completeDTO);
            // 自动流转
            workFlowContextBService.autoFlow(orderWork.getOrderId(), orderWork.getWorkId());
        } catch (OmsBaseException e) {
            log.info("#CollectionNotPay# 订单号：{} 步骤7 完成订单并完成跟单失败：{}", e.getMessage(), orderWork.getOrderId());
        }
    }

    private boolean getOrderPayNotes(Long orderId) {
        List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(orderId);
        Integer warrantyPaymentAmount = orderPays.stream()
                .filter(x -> Objects.equals(x.getAmountType(), OrderPayConsts.ORDER_PAY_MASTER)
                        && Objects.equals(PayConsts.PAY_TRADE_TYPE_INTIME, x.getTradeType())
                        && Objects.equals(PayConsts.PAY_CHANNEL_PLATFORM_DEPOSIT, x.getPayChannelId()))
                .mapToInt(OrderPay::getAmount).sum();
        return NumberUtil.isNotNullOrZero(warrantyPaymentAmount);
    }

    private void updateMasterAmountPay(OrderWork orderWork, Integer amount, Integer payStatus) {
        int masterAmount = orderWork.getMasterAmount() - amount;
        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setMasterAmount(masterAmount);
        updateOrderWork.setMasterPayChannelId(PayConsts.PAY_CHANNEL_PLATFORM_DEPOSIT);
        updateOrderWork.setMasterPayTime(new Date());
        updateOrderWork.setPayTime(new Date());
        if (NumberUtil.isNotNullOrZero(payStatus)) {
            updateOrderWork.setMasterPayStatus(payStatus);
            updateOrderWork.setPayStatus(payStatus);
        }
        updateOrderWork.setOrderId(orderWork.getOrderId());
        updateOrderWork.setWorkId(orderWork.getWorkId());
        orderWorkAmountService.updateMasterAmountPay(updateOrderWork);
    }


    @Override
    public void sendAppPushMessage(OrderWork orderWork, Integer amount, Long trackId) {
        try {
            JSONObject params = new JSONObject();
            params.put("order_id", orderWork.getOrderId());
            params.put("amount", NumberUtil.convertMoneyToYuan(amount));
            AppMessageDTO appMessage = new AppMessageDTO();
            appMessage.setOrderId(orderWork.getOrderId());
            appMessage.setPlat(orderWork.getPlat());
            appMessage.setMasterIdList(Collections.singletonList(orderWork.getMasterId()));
            appMessage.setRuleCode(String.valueOf(MessageRuleIdConsts.ZMN_COLLECTION_NOT_PAY_MQ_CODE));
            appMessage.setParams(params.toJSONString());
            messageSendBaseService.batchSendAndroidAndIOSMessage(appMessage);
            log.info("#CollectionNotPay# 订单号：{} 发送收款未支付APP_PUSH消息{}", orderWork.getOrderId(), JSON.toJSONString(appMessage));

        } catch (Exception e) {
            log.error("#CollectionNotPay# 订单号：{} 发送收款未支付APP_PUSH消息失败", orderWork.getOrderId());
        }
    }

    @Override
    public void robotCall(OrderWork orderWork, Integer amount, Long trackId) {
        try {
            String bizCallId = String.valueOf(orderWork.getOrderId() + trackId);
            ForeignEngineerBasicInfoDRO basicInfo = DubboResponseUtils.resultToThrow(() -> engineerListRemoteService.getEngineerById(orderWork.getMasterId()));
            RemindRequestDIO remindRequest = new RemindRequestDIO();
            remindRequest.setAppId(AppTypeEnum.OMS.getCode());
            remindRequest.setScenesType(ScenesTypeEnum.NO_PAY_COLLECTION.getCode());
            remindRequest.setBizId(String.valueOf(orderWork.getOrderId()));
            remindRequest.setBizCallId(bizCallId);
            remindRequest.setPhone(basicInfo.getMobile());
            remindRequest.setOperator("系统");
            List<VoiceVariateDIO> variates = new ArrayList<>();
            VoiceVariateDIO voiceVariate = new VoiceVariateDIO();
            voiceVariate.setVariateName("{$order_id}");
            voiceVariate.setVariateText(String.valueOf(orderWork.getOrderId()));
            variates.add(voiceVariate);
            voiceVariate = new VoiceVariateDIO();
            voiceVariate.setVariateName("{$amount}");
            voiceVariate.setVariateText(NumberUtil.convertMoneyToYuan(amount));
            variates.add(voiceVariate);
            remindRequest.setVariates(variates);
            // 30秒后没有打电话就放弃
            remindRequest.setExpireDuration(30);
            String content = JSON.toJSONString(remindRequest);
            // 发送异步消息队列
            zmnMQSender.sendSync(MessageQueueTopicConstant.ZMN_TOPIC_REMIND, MqConst.REMIND_REQUEST_TAG, bizCallId, content);
            log.info("#CollectionNotPay# 订单号：{} 发送收款未支付机器人打电话 {}", orderWork.getOrderId(), content);
        } catch (ZmnMQException e) {
            log.info("#CollectionNotPay# 订单号：{} 发送收款未支付机器人打电话失败：{}", orderWork.getOrderId(), e.getMessage());
        }
    }
}
